Skip to content

Add FP8/FP4 block-quantized support to GatherBlockQuantized contrib op - #32480

Merged
Tianlei Wu (tianleiwu) merged 76 commits into
mainfrom
copilot/research-onnx-runtime-support
Sep 15, 2026
Merged

Tianlei Wu (tianleiwu) merged 76 commits into
mainfrom
copilot/research-onnx-runtime-support

Conversation

Copilot AI commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Description

This PR extends GatherBlockQuantized (schema + CPU/CUDA/WebGPU kernels) to support FP8 and FP4 block-quantized data in addition to its existing integer formats.

Key semantic additions and fixes:

  • Adds float8e4m3fn, float8e4m3fnuz, float8e5m2, float8e5m2fnuz, and float4e2m1 data. For these types, bits is ignored and zero_points is omitted.
  • Allows block_size = 0 for FP8/FP4, meaning the full quantize_axis dimension is one block.
  • Allows FP scales to broadcast on axes other than quantize_axis.
  • Changes existing integer behavior as well as FP behavior: out-of-range indices now consistently produce zero output slices on CPU, CUDA, and WebGPU. This deliberately differs from ONNX Gather; it avoids provider-dependent behavior and preserves asynchronous CUDA execution without stream synchronization. Op-owner sign-off is requested for this contract change.
  • Aligns CUDA defaults with the schema (block_size = 128, quantize_axis = 1) and validates axes, ranks, scale shapes, empty outputs, launch dimensions, and integer bits values.
  • Validates block sizes and integer bits during graph resolution; bits remains intentionally ignored for FP8/FP4.
  • Makes the WebGPU FP8/FP4 path reachable and tests constant FP tables across supported providers.

Tests cover CPU/CUDA/WebGPU behavior, defaults, BFloat16 output, packed FP4 row boundaries, negative axes and indices, invalid indices, empty outputs, and invalid attributes. Generated contrib operator/kernel documentation is included.

Motivation and Context

Qwen3.8-Flash / Qwen4-Exp requires an n-gram embedding gather over a block-quantized FP8/FP4 table. Extending GatherBlockQuantized keeps a single Gather-with-quantization op while adding the dtype and broadcast-scale support required by that table.

Copilot AI and others added 30 commits August 25, 2026 20:18
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
…eek-engram' into copilot/add-op-support-for-qwen-3-8-flash-next

Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
…ids, head_offsets

Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
…utput

Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
…ids, head_offsets

Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
…utput

Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
…) support

Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Copilot AI and others added 2 commits September 14, 2026 22:07
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
…3-8-flash-next' into copilot/research-onnx-runtime-support

# Conflicts:
#	docs/ContribOperators.md

Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
…3-8-flash-next' into copilot/research-onnx-runtime-support

Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>

@tianleiwu Tianlei Wu (tianleiwu) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for folding this into GatherBlockQuantized rather than shipping a second contrib op, and for the previous round: the WebGPU FP path is now reachable and locale-safe, the dead scale_size field is gone, the TArray rank-8 limit has a real message, the CPU FP path regained the per-thread row cache plus an incremental scale-index update instead of a full per-element decomposition, the unrelated MLAS/engram changes are split out, and the new BFloat16 / odd-nibble FP4 row / negative-index / defaults tests close the coverage gaps. All of my earlier threads are resolved.

Requesting changes on one blocker plus one semantic change that needs an explicit decision.

Blocking

The branch does not compile — every Linux, CUDA, TensorRT, WebGPU, ARM64, and minimal leg fails on the same error in contrib_ops/cpu/quantization/gather_block_quantized.cc (memset on MLFloat16 under -Werror=class-memaccess). Inline comments on both sites. Because this aborts the build early, more issues may surface once it is fixed.

Needs a decision

Out-of-range indices now zero-fill on CPU for the pre-existing integer types too. The CPU ORT_ENFORCE is replaced by a zero-fill, the schema text "It is an error if any of the index values are out of bounds" is deleted, and InvalidIndices flips from expect-failure to expect-success. That is not FP8/FP4-scoped — already-shipped int4/uint4/uint8 models go from a hard error to silently-zero output, diverging from ONNX Gather. It does make CPU match the pre-existing CUDA/WebGPU behavior, so there is a consistency argument, but it deserves an explicit owner sign-off and a mention in the title/description rather than riding along in a dtype-extension PR. Inline comment on the schema text.

Other suggestions (non-blocking)

  1. ORT_ENFORCE is used for scales-shape validation at contrib_ops/cuda/quantization/gather_block_quantized.cc:217, two lines below an ORT_RETURN_IF_NOT in the same block. Prefer ORT_RETURN_IF_NOT for user-input validation so the failure comes back as a Status.

  2. GatherBlockQuantizedParam grew by three TArray<int64_t> (192 bytes) that are passed by value into LaunchGatherBlockQuantizedKernel on every launch, including the integer paths that never read them. scale_broadcast_axis in particular only needs a flag per axis — TArray<int32_t> or a bitmask would halve/eliminate that cost.

  3. docs/ContribOperators.md loses its trailing blank line at EOF in this diff. Please confirm it was regenerated by tools/python/gen_contrib_doc.py rather than hand-edited, otherwise the Doc Gen check will keep reverting it.

  4. The WGSL LUT is emitted as const kFpDequantLut = array<f32, 256>(...) and indexed with a runtime u32. No other shader in the repo dynamically indexes a module-scope const array. Worth confirming Tint/Dawn accepts it (rather than requiring a var<private> array) once the WebGPU leg gets past the compile break.

  5. Test gaps:

    • No FP8 case with a non-zero block_size where data_shape[quantize_axis] % block_size != 0. That is exactly the "reset the block index at every quantize-axis row boundary" case both the CUDA and CPU comments call out as the reason for the generic per-axis decomposition; FpSubRowBlockScale uses [1, 32] with block_size = 16, i.e. an exact multiple on a single row, so it never exercises it.
    • No scale broadcast on a middle axis (non-leading and non-quantize). FpGlobalPerTensorScale only broadcasts axis 0.

Comment thread onnxruntime/contrib_ops/cpu/quantization/gather_block_quantized.cc Outdated
Comment thread onnxruntime/contrib_ops/cpu/quantization/gather_block_quantized.cc Outdated
Comment thread onnxruntime/contrib_ops/cuda/quantization/gather_block_quantized.cu Outdated
Comment thread onnxruntime/core/graph/contrib_ops/contrib_defs.cc Outdated
Comment thread onnxruntime/core/graph/contrib_ops/contrib_defs.cc
Comment thread onnxruntime/core/graph/contrib_ops/contrib_defs.cc
Copilot AI and others added 3 commits September 15, 2026 00:43
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
…3-8-flash-next' into copilot/research-onnx-runtime-support

# Conflicts:
#	docs/ContribOperators.md

Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Copilot AI and others added 3 commits September 15, 2026 15:23
…3-8-flash-next' into copilot/research-onnx-runtime-support

Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
@kunal-vaishnavi
kunal-vaishnavi removed this pull request from stack #32481 September 15, 2026 16:16
@kunal-vaishnavi
kunal-vaishnavi added this pull request to stack #32614 September 15, 2026 16:16
Base automatically changed from copilot/add-op-support-for-qwen-3-8-flash-next to main September 15, 2026 20:35

@tianleiwu Tianlei Wu (tianleiwu) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current head addresses all substantive concerns from my previous review: the CPU half-output build failure is fixed, the out-of-range behavior is explicitly documented, CUDA validation and coverage are improved, and the WebGPU FP8/FP4 path is now registered and exercised with constant inputs. I also checked the final WebGPU lookup-table change: storing raw u32 bit patterns and bitcasting the selected runtime value avoids non-finite constant-expression failures without losing FP codes. The reported CI matrix is green. One non-blocking generated-doc whitespace cleanup remains inline.

Comment thread docs/ContribOperators.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants